//Nodis = Node Dictionary System
const moment = require('moment');
const { toLog } = require('./common/common');
//缓存类
class Nodis {
    constructor() {
        //所有的缓存数据都应区分数据库
        this.tableDefine = {};      // {tableName : {data,createTime}}
        this.hash = {};             // {tableName : {data,createTime}}
        this.dbSet = {};            // {原生数据}       //一般不删除        注意dbSet不需要传name
        this.tableData = {};        // 重点关注 需要定时清理的数据 {tableName : {data,createTime}}
        this.tableDetail = {};      // 表的主键 列数量信息 : {key,num},
        this.bpTree = {};           // 表的B+树索引数据结构
        setInterval(async () => {
            await this.clear();
        }, ini.db.clearCache * 1000);
    }

    async put(type, name, data, dbName) {
        const createTime = moment().valueOf();
        if (type === 'tableDefine') {
            if (!this.tableDefine[dbName]) {
                this.tableDefine[dbName] = {};
            }
            this.tableDefine[dbName][name] = {
                data, createTime,
            }
        } else if (type === 'hash') {
            if (!this.hash[dbName]) {
                this.hash[dbName] = {};
            }
            this.hash[dbName][name] = {
                data, createTime,
            }
        } else if (type === 'dbSet') {
            if (!this.dbSet) {
                this.dbSet = {};
            }
            this.dbSet = {
                data, createTime,
            }
        } else if (type === 'tableData') {
            if (!this.tableData[dbName]) {
                this.tableData[dbName] = {};
            }
            this.tableData[dbName][name] = {
                data, createTime,
            }
        } else if (type === 'tableDetail') {
            if (!this.tableDetail[dbName]) {
                this.tableDetail[dbName] = {};
            }
            this.tableDetail[dbName][name] = {
                data, createTime,
            }
        } else if (type === 'bpTree') {
            if (!this.bpTree[dbName]) {
                this.bpTree[dbName] = {};
            }
            this.bpTree[dbName][name] = {
                data, createTime,
            }
        } else {
            throw ("UNKNOWN_ERROR");
        }

    }

    async get(type, name, dbName) {
        const createTime = moment().valueOf();      //每次取更新时间
        if (type === 'tableDefine') {
            if (this.tableDefine[dbName] && this.tableDefine[dbName][name]) {
                this.tableDefine[dbName][name].createTime = createTime;
                return this.tableDefine[dbName][name].data || null;
            } else {
                return null;
            }
        } else if (type === 'hash') {
            if (this.hash[dbName] && this.hash[dbName][name]) {
                this.hash[dbName][name].createTime = createTime;
                return this.hash[dbName][name].data || null;
            } else {
                return null;
            }
        } else if (type === 'dbSet') {
            if (this.dbSet) {
                this.dbSet.createTime = createTime;
                return this.dbSet.data || null;
            } else {
                return null;
            }
        } else if (type === 'tableData') {
            if (this.tableData[dbName] && this.tableData[dbName][name]) {
                this.tableData[dbName][name].createTime = createTime;
                return this.tableData[dbName][name].data || null;
            } else {
                return null;
            }
        } else if (type === 'tableDetail') {
            if (this.tableDetail[dbName] && this.tableDetail[dbName][name]) {
                this.tableDetail[dbName][name].createTime = createTime;
                return this.tableDetail[dbName][name].data || null;
            } else {
                return null;
            }
        } else if (type === 'bpTree') {
            if (this.bpTree[dbName] && this.bpTree[dbName][name]) {
                this.bpTree[dbName][name].createTime = createTime;
                return this.bpTree[dbName][name].data || null;
            } else {
                return null;
            }
        } else {
            throw ("UNKNOWN_ERROR");
        }
    }

    //定时清理函数  后续调整
    async clear() {
        const now = moment().valueOf();
        for (let key in this.tableDefine) {
            for (let subkey in this.tableDefine[key]) {
                let createTime = this.tableDefine[key][subkey].createTime;
                if (moment(now).diff(moment(createTime), 'seconds') > ini.db.cacheInvalid) {
                    delete this.tableDefine[key][subkey];
                    toLog("定时删除了 tableDefine", key, subkey);
                }
            }
        }
        for (let key in this.tableDetail) {
            for (let subkey in this.tableDetail[key]) {
                let createTime = this.tableDetail[key][subkey].createTime;
                if (moment(now).diff(moment(createTime), 'seconds') > ini.db.cacheInvalid) {
                    delete this.tableDetail[key][subkey];
                    toLog("定时删除了 tableDetail", key, subkey);
                }
            }
        }
        for (let key in this.tableData) {
            for (let subkey in this.tableData[key]) {
                let createTime = this.tableData[key][subkey].createTime;
                if (moment(now).diff(moment(createTime), 'seconds') > ini.db.cacheInvalid) {
                    delete this.tableData[key][subkey];
                    toLog("定时删除了 tableData", key, subkey);
                }
            }
        }
        for (let key in this.hash) {
            for (let subkey in this.hash[key]) {
                let createTime = this.hash[key][subkey].createTime;
                if (moment(now).diff(moment(createTime), 'seconds') > ini.db.cacheInvalid) {
                    delete this.hash[key][subkey];
                    toLog("定时删除了 hash", key, subkey);
                }
            }
        }
        for (let key in this.bpTree) {
            for (let subkey in this.bpTree[key]) {
                let createTime = this.bpTree[key][subkey].createTime;
                if (moment(now).diff(moment(createTime), 'seconds') > ini.db.cacheInvalid) {
                    delete this.bpTree[key][subkey];
                    toLog("定时删除了 bpTree", key, subkey);
                }
            }
        }
    }

    //主动删除Nodis的缓存 一般用于insert和update,delete语句
    async initiativeClear(type, name, dbName) {
        if (type === 'tableDefine') {
            if (this.tableDefine[dbName] && this.tableDefine[dbName][name]) {
                delete this.tableDefine[dbName][name];
                toLog('清理了表主键和行定义缓存');
            }
        } else if (type === 'hash') {
            if (this.hash[dbName] && this.hash[dbName][name]) {
                delete this.hash[dbName][name];
                toLog('清理了哈希缓存');
            }
        } else if (type === 'dbSet') {
            if (this.dbSet) {
                this.dbSet = {};                //这个不要乱删啊
            }
        } else if (type === 'tableData') {
            if (this.tableData[dbName] && this.tableData[dbName][name]) {
                delete this.tableData[dbName][name];
                toLog('清理了行缓存');
            }
        } else if (type === 'tableDetail') {
            if (this.tableDetail[dbName] && this.tableDetail[dbName][name]) {
                toLog('清理了表结构缓存');
                delete this.tableDetail[dbName][name];
            }
        }
        else if (type === 'bpTree') {
            if (this.bpTree[dbName] && this.bpTree[dbName][name]) {
                toLog('清理了B+树缓存');
                delete this.bpTree[dbName][name];
                toLog("清理后的缓存为 ", this.bpTree);
            }
        }
        return;
    }

    //清理所有表相关的缓存 types为数组 数据库名按理说是同一个
    async clearTableCache(types, name, dbName) {
        toLog("开始主动清理缓存")
        for (let i = 0; i < types.length; i++) {
            toLog(types[i])
            await this.initiativeClear(types[i], name, dbName);
        }
        return;
    }

    //清理所有数据库相关的缓存
    async clearDbCache(name) {
        delete this.dbSet[name];
        return;
    }

    //调试用
    async show() {
        // this.tableDefine = {};      // {tableName : {data,createTime}}
        // this.hash = {};             // {tableName : {data,createTime}}
        // this.dbSet = {};            // {原生数据}       //一般不删除        注意dbSet不需要传name
        // this.tableData = {};        // 重点关注 需要定时清理的数据 {tableName : {data,createTime}}
        // this.tableDetail = {};      // 表的主键 列数量信息 : {key,num},
        // this.bpTree = {};           // 表的B+树索引数据结构
        toLog("this.tableDefine = ", this.tableDefine);
        toLog('hash = ', this.hash);
        toLog("dbSet = ", this.dbSet);
        toLog("tableData = ", this.tableData);
        toLog("tableDetail = ", this.tableDetail);
        toLog("bpTree = ", this.bpTree);
    }
}


module.exports = Nodis;